#include "stdafx.h"
#include "cppflibinc.h"


using namespace cppflib;
using namespace cppflib::io;
using namespace cppflib::os;
using namespace cppflib::collections;

static void TestWriteFile_UTF16Normal(pcwstr_t filePath, FileStream::fileencoding_t enc)
{
   cppmempool::MemPoolWrap memPool;

   try {
      CFString str;
      FileStream *fs = new FileStream(filePath, FileStream::FA_WRITE);
      fs->SetOutputEncoding(enc);
      fs->SetOutputNewLine(FileStream::NL_CRLF);
      fs->WriteBOM();
   
      assert(fs->Lock(0, 10));

      str.Format(_S("Hello"));
      fs->WriteLine(str);
      str.Format(_S("world"));
      fs->WriteLine(str);
      str.Format(_S("..."));
      fs->WriteLine(str);
      fs->Flush();

      assert(fs->Unlock(0, 10));

      fs->Close();
   } 
   catch(IOException &exp) {
      debug::Print(exp.GetMsg());
   }

}

static void TestAppendFile_UTF16Normal(pcwstr_t filePath, FileStream::fileencoding_t enc)
{
   cppmempool::MemPoolWrap memPool;

   try {
      CFString str;
      FileStream *fs = new FileStream(filePath, FileStream::FA_APPEND);
      fs->SetOutputEncoding(enc);
      fs->SetOutputNewLine(FileStream::NL_CRLF);

      str.Format(_S("<<<<>>>>"));
      fs->WriteLine(str);
      str.Format(_S("||||||||"));
      fs->WriteLine(str);
      str.Format(_S("..."));
      fs->WriteLine(str);

      fs->Close();
   } 
   catch(IOException &exp) {
      debug::Print(exp.GetMsg());
   }
}

static void TestReadFile_UTF16Normal(pcwstr_t filePath, FileStream::fileencoding_t enc)
{
   cppmempool::MemPoolWrap memPool;

   try {
      CFString str;
      FileStream *fs = new FileStream(filePath, FileStream::FA_READ_DETECTENC);
      
      if (fs->GetInputEncoding() == FileStream::ENC_UTF8)
         assert(fs->GetFileSize() == I64N(22));
      else
         assert(fs->GetFileSize() == I64N(40));
      assert(fs->ReadLine(str));
      assert(str.Compare(_S("Hello")) == 0);
      assert(fs->ReadLine(str));
      assert(str.Compare(_S("world")) == 0);
      assert(fs->ReadLine(str));
      assert(str.Compare(_S("...")) == 0);
      assert(!fs->ReadLine(str));

      fs->Close();
   } 
   catch(IOException &exp) {
      debug::Print(exp.GetMsg());
   }
}

static void TestReadAfterAppend_UTF16Normal(pcwstr_t filePath, FileStream::fileencoding_t enc)
{
   cppmempool::MemPoolWrap memPool;

   try {
      CFString str;
      FileStream *fs = new FileStream(filePath, FileStream::FA_READ_DETECTENC);
      
      assert(fs->ReadLine(str));
      assert(str.Compare(_S("Hello")) == 0);
      assert(fs->ReadLine(str));
      assert(str.Compare(_S("world")) == 0);
      assert(fs->ReadLine(str));
      assert(str.Compare(_S("...")) == 0);
      assert(fs->ReadLine(str));
      assert(str == _S("<<<<>>>>"));
      assert(fs->ReadLine(str));
      assert(str == _S("||||||||"));
      assert(fs->ReadLine(str));
      assert(str == _S("..."));
      assert(!fs->ReadLine(str));

      fs->Close();
   } 
   catch(IOException &exp) {
      debug::Print(exp.GetMsg());
   }
}

static void TestWriteFile_UTF16NoByte(pcwstr_t filePath, FileStream::fileencoding_t enc)
{
   cppmempool::MemPoolWrap memPool;

   try {
      FileStream *fs = new FileStream(filePath, FileStream::FA_WRITE);
      fs->SetOutputEncoding(enc);
      fs->SetOutputNewLine(FileStream::NL_CRLF);
      fs->WriteBOM();
 
      fs->Close();
   } 
   catch(IOException &exp) {
      debug::Print(exp.GetMsg());
   }
}

static void TestReadFile_UTF16NoByte(pcwstr_t filePath, FileStream::fileencoding_t enc)
{
   cppmempool::MemPoolWrap memPool;

   try {
      CFString str;
      FileStream *fs = new FileStream(filePath, FileStream::FA_READ_DETECTENC);
      assert(fs->GetInputEncoding() == enc);
      assert(!fs->ReadLine(str));
      fs->Close();
   } 
   catch(IOException &exp) {
      debug::Print(exp.GetMsg());
   }
}

static void TestWriteFile_UTF16SingleByte(pcwstr_t filePath, FileStream::fileencoding_t enc)
{
   cppmempool::MemPoolWrap memPool;

   try {
      FileStream *fs = new FileStream(filePath, FileStream::FA_WRITE);
      fs->SetOutputEncoding(enc);
      fs->SetOutputNewLine(FileStream::NL_CRLF);
      fs->WriteBOM();
      fs->Write((u8_t)0x22);
 
      fs->Close();
   } 
   catch(IOException &exp) {
      debug::Print(exp.GetMsg());
   }
}

static void TestReadFile_UTF16SingleByte(pcwstr_t filePath, FileStream::fileencoding_t enc)
{
   cppmempool::MemPoolWrap memPool;

   try {
      CFString str;
      FileStream *fs = new FileStream(filePath, FileStream::FA_READ_DETECTENC);
      assert(fs->GetInputEncoding() == enc);
      assert(!fs->ReadLine(str));
      fs->Close();
   } 
   catch(IOException &exp) {
      debug::Print(exp.GetMsg());
   }
}

static void TestWriteFile_UTF16OddNumByte(pcwstr_t filePath, FileStream::fileencoding_t enc)
{
   cppmempool::MemPoolWrap memPool;

   try {
      CFString str("helloworld");
      FileStream *fs = new FileStream(filePath, FileStream::FA_WRITE);
      fs->SetOutputEncoding(enc);
      fs->SetOutputNewLine(FileStream::NL_CRLF);
      fs->WriteBOM();
      for (int i = 0; i < 10; ++i)
         fs->Write(str);
      fs->Write((u8_t)0x30);
 
      fs->Close();
   } 
   catch(IOException &exp) {
      debug::Print(exp.GetMsg());
   }
}

static void TestReadFile_UTF16OddNumByte(pcwstr_t filePath, FileStream::fileencoding_t enc)
{
   cppmempool::MemPoolWrap memPool;

   try {
      CFString str;
      FileStream *fs = new FileStream(filePath, FileStream::FA_READ_DETECTENC);
      assert(fs->GetInputEncoding() == enc);
      assert(fs->ReadLine(str));
      assert(str.Compare(_S("helloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworld")) == 0);
      assert(!fs->ReadLine(str));
      fs->Close();
   } 
   catch(IOException &exp) {
      debug::Print(exp.GetMsg());
   }
}

static void TestWriteFile_UTF16LastLineNoLineFeed(pcwstr_t filePath, FileStream::fileencoding_t enc)
{
   cppmempool::MemPoolWrap memPool;

   try {
      CFString str("hello world");
      FileStream *fs = new FileStream(filePath, FileStream::FA_WRITE);
      fs->SetOutputEncoding(enc);
      fs->SetOutputNewLine(FileStream::NL_CRLF);
      fs->WriteBOM();
      for (int i = 0; i < 10; ++i)
         fs->WriteLine(str);
      fs->Write(str);
 
      fs->Close();
   } 
   catch(IOException &exp) {
      debug::Print(exp.GetMsg());
   }
}

static void TestReadFile_UTF16LastLineNoLineFeed(pcwstr_t filePath, FileStream::fileencoding_t enc)
{
   cppmempool::MemPoolWrap memPool;

   try {
      CFString str;
      FileStream *fs = new FileStream(filePath, FileStream::FA_READ_DETECTENC);
      assert(fs->GetInputEncoding() == enc);
      for (int i = 0; i < 10; ++i) {
         assert(fs->ReadLine(str));
         assert(str.Compare(_S("hello world")) == 0);
      }
      assert(fs->ReadLine(str));
      assert(str.Compare(_S("hello world")) == 0);
      assert(!fs->ReadLine(str));
      fs->Close();
   } 
   catch(IOException &exp) {
      debug::Print(exp.GetMsg());
   }
}

static void TestWriteFile_UTF16LongLine(pcwstr_t filePath, FileStream::fileencoding_t enc)
{
   cppmempool::MemPoolWrap memPool;

   try {
      CFString str("helloworld");
      FileStream *fs = new FileStream(filePath, FileStream::FA_WRITE);
      fs->SetOutputEncoding(enc);
      fs->SetOutputNewLine(FileStream::NL_CRLF);
      fs->WriteBOM();
      for (int i = 0; i < 40; ++i)
         fs->Write(str);
      str.Format(_S("$$$hello world***"));
      fs->WriteLine(str);
 
      fs->Close();
   } 
   catch(IOException &exp) {
      debug::Print(exp.GetMsg());
   }
}

static void TestReadFile_UTF16LongLine(pcwstr_t filePath, FileStream::fileencoding_t enc)
{
   cppmempool::MemPoolWrap memPool;

   try {
      CFString str;
      FileStream *fs = new FileStream(filePath, FileStream::FA_READ_DETECTENC);
      assert(fs->GetInputEncoding() == enc);
      assert(fs->ReadLine(str));
      assert(str.Compare(_S("helloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworld$$$hello world***")) == 0);
      assert(!fs->ReadLine(str));
      fs->Close();
   } 
   catch(IOException &exp) {
      debug::Print(exp.GetMsg());
   }
}

static void TestWriteFile_UTF16_2LongLines(pcwstr_t filePath, FileStream::fileencoding_t enc)
{
   cppmempool::MemPoolWrap memPool;

   try {
      CFString str("helloworld");
      FileStream *fs = new FileStream(filePath, FileStream::FA_WRITE);
      fs->SetOutputEncoding(enc);
      fs->SetOutputNewLine(FileStream::NL_CRLF);
      fs->WriteBOM();

      // first line
      for (int i = 0; i < 40; ++i)
         fs->Write(str);
      str.Format(_S("$$$hello world***"));
      fs->WriteLine(str);

      // second line (no line feed)
      str.Format(_S(" _ _ @@ _ _ "));
      for (int i = 0; i < 30; ++i)
         fs->Write(str);
 
      fs->Close();
   } 
   catch(IOException &exp) {
      debug::Print(exp.GetMsg());
   }
}

static void TestReadFile_UTF16_2LongLines(pcwstr_t filePath, FileStream::fileencoding_t enc)
{
   cppmempool::MemPoolWrap memPool;

   try {
      CFString str;
      FileStream *fs = new FileStream(filePath, FileStream::FA_READ_DETECTENC);
      assert(fs->GetInputEncoding() == enc);
      assert(fs->ReadLine(str));
      assert(str.Compare(_S("helloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworld$$$hello world***")) == 0);
      assert(fs->ReadLine(str));
      assert(str.Compare(_S(" _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _ ")) == 0);
      assert(!fs->ReadLine(str));
      fs->Close();
   } 
   catch(IOException &exp) {
      debug::Print(exp.GetMsg());
   }
}

static void TestWriteFile_UTF8Normal(pcwstr_t filePath)
{
   cppmempool::MemPoolWrap memPool;

   try {
      CFString str;
      FileStream *fs = new FileStream(filePath, FileStream::FA_WRITE);
      fs->SetOutputEncoding(FileStream::ENC_UTF8);
      fs->SetOutputNewLine(FileStream::NL_CRLF);
      fs->WriteBOM();
   
      str.Format(_S("Hello"));
      fs->WriteLine(str);
      str.Format(_S("world"));
      fs->WriteLine(str);
      str.Format(_S("..."));
      fs->WriteLine(str);

      fs->Close();
   } 
   catch(IOException &exp) {
      debug::Print(exp.GetMsg());
   }

}

static void TestReadFile_UTF8Normal(pcwstr_t filePath)
{
   cppmempool::MemPoolWrap memPool;

   try {
      CFString str;
      FileStream *fs = new FileStream(filePath, FileStream::FA_READ_DETECTENC);
      
      assert(fs->ReadLine(str));
      assert(str.Compare(_S("Hello")) == 0);
      assert(fs->ReadLine(str));
      assert(str.Compare(_S("world")) == 0);
      assert(fs->ReadLine(str));
      assert(str.Compare(_S("...")) == 0);
      assert(!fs->ReadLine(str));

      fs->Close();
   } 
   catch(IOException &exp) {
      debug::Print(exp.GetMsg());
   }
}

static void TestWriteFile_UTF8NoByte(pcwstr_t filePath)
{
   cppmempool::MemPoolWrap memPool;

   try {
      FileStream *fs = new FileStream(filePath, FileStream::FA_WRITE);
      fs->SetOutputEncoding(FileStream::ENC_UTF8);
      fs->SetOutputNewLine(FileStream::NL_CRLF);
      fs->WriteBOM();
 
      fs->Close();
   } 
   catch(IOException &exp) {
      debug::Print(exp.GetMsg());
   }
}

static void TestReadFile_UTF8NoByte(pcwstr_t filePath)
{
   cppmempool::MemPoolWrap memPool;

   try {
      CFString str;
      FileStream *fs = new FileStream(filePath, FileStream::FA_READ_DETECTENC);
      assert(fs->GetInputEncoding() == FileStream::ENC_UTF8);
      assert(!fs->ReadLine(str));
      fs->Close();
   } 
   catch(IOException &exp) {
      debug::Print(exp.GetMsg());
   }
}

static void TestWriteFile_UTF8LastLineNoLineFeed(pcwstr_t filePath)
{
   cppmempool::MemPoolWrap memPool;

   try {
      CFString str("hello world");
      FileStream *fs = new FileStream(filePath, FileStream::FA_WRITE);
      fs->SetOutputEncoding(FileStream::ENC_UTF8);
      fs->SetOutputNewLine(FileStream::NL_CRLF);
      fs->WriteBOM();
      for (int i = 0; i < 10; ++i)
         fs->WriteLine(str);
      fs->Write(str);
 
      fs->Close();
   } 
   catch(IOException &exp) {
      debug::Print(exp.GetMsg());
   }
}

static void TestReadFile_UTF8LastLineNoLineFeed(pcwstr_t filePath)
{
   cppmempool::MemPoolWrap memPool;

   try {
      CFString str;
      FileStream *fs = new FileStream(filePath, FileStream::FA_READ_DETECTENC);
      assert(fs->GetInputEncoding() == FileStream::ENC_UTF8);
      for (int i = 0; i < 10; ++i) {
         assert(fs->ReadLine(str));
         assert(str.Compare(_S("hello world")) == 0);
      }
      assert(fs->ReadLine(str));
      assert(str.Compare(_S("hello world")) == 0);
      assert(!fs->ReadLine(str));
      fs->Close();
   } 
   catch(IOException &exp) {
      debug::Print(exp.GetMsg());
   }
}

static void TestWriteFile_UTF8LongLine(pcwstr_t filePath)
{
   cppmempool::MemPoolWrap memPool;

   try {
      CFString str("helloworld");
      FileStream *fs = new FileStream(filePath, FileStream::FA_WRITE);
      fs->SetOutputEncoding(FileStream::ENC_UTF8);
      fs->SetOutputNewLine(FileStream::NL_CRLF);
      fs->WriteBOM();
      for (int i = 0; i < 40; ++i)
         fs->Write(str);
      str.Format(_S("$$$hello world***"));
      fs->WriteLine(str);
 
      fs->Close();
   } 
   catch(IOException &exp) {
      debug::Print(exp.GetMsg());
   }
}

static void TestReadFile_UTF8LongLine(pcwstr_t filePath)
{
   cppmempool::MemPoolWrap memPool;

   try {
      CFString str;
      FileStream *fs = new FileStream(filePath, FileStream::FA_READ_DETECTENC);
      assert(fs->GetInputEncoding() == FileStream::ENC_UTF8);
      assert(fs->ReadLine(str));
      assert(str.Compare(_S("helloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworld$$$hello world***")) == 0);
      assert(!fs->ReadLine(str));
      fs->Close();
   } 
   catch(IOException &exp) {
      debug::Print(exp.GetMsg());
   }
}

static void TestWriteFile_UTF8_2LongLines(pcwstr_t filePath)
{
   cppmempool::MemPoolWrap memPool;

   try {
      CFString str("helloworld");
      FileStream *fs = new FileStream(filePath, FileStream::FA_WRITE);
      fs->SetOutputEncoding(FileStream::ENC_UTF8);
      fs->SetOutputNewLine(FileStream::NL_CRLF);
      fs->WriteBOM();

      // first line
      for (int i = 0; i < 40; ++i)
         fs->Write(str);
      str.Format(_S("$$$hello world***"));
      fs->WriteLine(str);

      // second line (no line feed)
      str.Format(_S(" _ _ @@ _ _ "));
      for (int i = 0; i < 30; ++i)
         fs->Write(str);
 
      fs->Close();
   } 
   catch(IOException &exp) {
      debug::Print(exp.GetMsg());
   }
}

static void TestReadFile_UTF8_2LongLines(pcwstr_t filePath)
{
   cppmempool::MemPoolWrap memPool;

   try {
      CFString str;
      FileStream *fs = new FileStream(filePath, FileStream::FA_READ_DETECTENC);
      assert(fs->GetInputEncoding() == FileStream::ENC_UTF8);
      assert(fs->ReadLine(str));
      assert(str.Compare(_S("helloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworldhelloworld$$$hello world***")) == 0);
      assert(fs->ReadLine(str));
      assert(str.Compare(_S(" _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _  _ _ @@ _ _ ")) == 0);
      assert(!fs->ReadLine(str));
      fs->Close();
   } 
   catch(IOException &exp) {
      debug::Print(exp.GetMsg());
   }
}

//////////////////////////////////////////////////////////////////////////////

static void TestDeleteFile(pcwstr_t filePath)
{
   os::DelFile(filePath);
}

static void TestReadWriteDel_UTF16Normal(pcwstr_t filePath, FileStream::fileencoding_t enc)
{
   TestWriteFile_UTF16Normal(filePath, enc);
   TestReadFile_UTF16Normal(filePath, enc);
   TestDeleteFile(filePath);
}

static void TestReadWriteDel_UTF16NoByte(pcwstr_t filePath, FileStream::fileencoding_t enc)
{
   TestWriteFile_UTF16NoByte(filePath, enc);
   TestReadFile_UTF16NoByte(filePath, enc);
   TestDeleteFile(filePath);
}

static void TestReadWriteDel_UTF16SingleByte(pcwstr_t filePath, FileStream::fileencoding_t enc)
{
   TestWriteFile_UTF16SingleByte(filePath, enc);
   TestReadFile_UTF16SingleByte(filePath, enc);
   TestDeleteFile(filePath);
}

static void TestReadWriteDel_UTF16OddNumByte(pcwstr_t filePath, FileStream::fileencoding_t enc)
{
   TestWriteFile_UTF16OddNumByte(filePath, enc);
   TestReadFile_UTF16OddNumByte(filePath, enc);
   TestDeleteFile(filePath);
}

static void TestReadWriteDel_UTF16LastLineNoLineFeed(pcwstr_t filePath, FileStream::fileencoding_t enc)
{
   TestWriteFile_UTF16LastLineNoLineFeed(filePath, enc);
   TestReadFile_UTF16LastLineNoLineFeed(filePath, enc);
   TestDeleteFile(filePath);
}

static void TestReadWriteDel_UTF16LongLine(pcwstr_t filePath, FileStream::fileencoding_t enc)
{
   TestWriteFile_UTF16LongLine(filePath, enc);
   TestReadFile_UTF16LongLine(filePath, enc);
   TestDeleteFile(filePath);
}

static void TestReadWriteDel_UTF16_2LongLines(pcwstr_t filePath, FileStream::fileencoding_t enc)
{
   TestWriteFile_UTF16_2LongLines(filePath, enc);
   TestReadFile_UTF16_2LongLines(filePath, enc);
   TestDeleteFile(filePath);
}

/////////////////////////////////////////////////////////////////////////////////////

static void TestReadWriteDel_UTF8Normal(pcwstr_t filePath)
{
   TestWriteFile_UTF8Normal(filePath);
   TestReadFile_UTF8Normal(filePath);
   TestDeleteFile(filePath);
}

static void TestReadWriteDel_UTF8NoByte(pcwstr_t filePath)
{
   TestWriteFile_UTF8NoByte(filePath);
   TestReadFile_UTF8NoByte(filePath);
   TestDeleteFile(filePath);
}

static void TestReadWriteDel_UTF8LastLineNoLineFeed(pcwstr_t filePath)
{
   TestWriteFile_UTF8LastLineNoLineFeed(filePath);
   TestReadFile_UTF8LastLineNoLineFeed(filePath);
   TestDeleteFile(filePath);
}

static void TestReadWriteDel_UTF8LongLine(pcwstr_t filePath)
{
   TestWriteFile_UTF8LongLine(filePath);
   TestReadFile_UTF8LongLine(filePath);
   TestDeleteFile(filePath);
}

static void TestReadWriteDel_UTF8_2LongLines(pcwstr_t filePath)
{
   TestWriteFile_UTF8_2LongLines(filePath);
   TestReadFile_UTF8_2LongLines(filePath);
   TestDeleteFile(filePath);
}



//////////////////////////////////////////////////////////////////////////////////////

static void TestAppendFile(pcwstr_t filePath)
{
   TestWriteFile_UTF16Normal(filePath, FileStream::ENC_UTF16LE);
   TestAppendFile_UTF16Normal(filePath, FileStream::ENC_UTF16LE);
   TestReadAfterAppend_UTF16Normal(filePath, FileStream::ENC_UTF16LE);
   TestDeleteFile(filePath);
}

static void TestReadNonExistingFile(pcwstr_t filePath)
{
   cppmempool::MemPoolWrap memPool;

   try {
      FileStream *fs = new FileStream(filePath, FileStream::FA_READ_DETECTENC);
      fs->Close();
   }
   catch (IOException &exp) {
      debug::Print(debug::DL_ERROR, exp.GetMsg());
   }
}

static void TestMemoryStream()
{
   debug::Print(_S("Testing memory stream...\n"));

   cppmempool::MemPoolWrap memPool;

   const int ARRAYSIZE = 26;
   ArrayByte * buffer = new ArrayByte(ARRAYSIZE);
   for (u32_t i = 0; i < buffer->GetSize(); ++i) {
      (*buffer)[i] = i + 97;
   }

   MemoryStream * memStream = new MemoryStream();
   assert(memStream->GetBufferSize() == 0);
   memStream->Write(*buffer);
   assert(memStream->GetBufferSize() == ARRAYSIZE);
   memStream->Write(*buffer, 0, 2);
   assert(memStream->GetBufferSize() == ARRAYSIZE + 2);
   memStream->Write((u8_t)0x41);
   assert(memStream->GetBufferSize() == ARRAYSIZE + 3);
   
   ArrayByte * readBuf = new ArrayByte(ARRAYSIZE);
   assert(memStream->Read() < 0);
   memStream->ResetPointer();
   assert(memStream->Read(*readBuf) == static_cast<int>(readBuf->GetSize()));
   for (u32_t i = 0; i < readBuf->GetSize(); ++i) {
      assert((*readBuf)[i] == i + 97);
   }

   assert(memStream->Read() == 97);
   assert(memStream->Read() == 98);
   assert(memStream->Read() == 0x41);
   assert(memStream->Read() < 0);
   
}

static void TestBufferedReadStream()
{
   cppmempool::MemPoolWrap memPool;

   const int ARRAYSIZE = 26;
   ArrayByte * buffer = new ArrayByte(ARRAYSIZE);
   for (u32_t i = 0; i < buffer->GetSize(); ++i) {
      (*buffer)[i] = i + 97;
   }

   MemoryStream * memStream = new MemoryStream();
   assert(memStream->GetBufferSize() == 0);
   memStream->Write(*buffer);
   memStream->ResetPointer();

   ArrayByte * readBuf = new ArrayByte(ARRAYSIZE);
   BufferedReadStream * bufStream = new BufferedReadStream(memStream, 5);
   assert(bufStream->Read(*readBuf, 0, 3) == 3);
   assert(bufStream->Read(*readBuf, 0, 10) == 10);
   bufStream->Seek(-4, Stream::S_CUR);
   assert(bufStream->Read() == 'j');
   assert(bufStream->Read() == 'k');
   assert(bufStream->Read(*readBuf, 0, 5) == 5);
   bufStream->Seek(-1, Stream::S_CUR);
   assert(bufStream->Read(*readBuf, 0, 8) == 8);
}

static ArrayWChar * __GetOriginalCharacters()
{
  wc_t testdoc_utf16BE_txt[] = {
  0x8c93, 0x718a, 0x5bf6, 0x5bf6, 0x51fa,
  0x751f, 0x5f8c, 0x4e00, 0x5ea6, 0x7591, 0x906d,
  0x6bcd, 0x89aa, 0x201c, 0x68c4, 0x990a, 0x201d,
  0xff0c, 0x751f, 0x7522, 0x5f8c, 0x4e00, 0x76f4,
  0x628a, 0x5bf6, 0x5bf6, 0x62b1, 0x5728, 0x80f8,
  0x524d, 0x7684, 0x201c, 0x771f, 0x771f, 0x201d,
  0x7a81, 0x7136, 0x653e, 0x958b, 0x5b69, 0x5b50,
  0xff0c, 0x81ea, 0x9867, 0x81ea, 0x5730, 0x5403,
  0x8d77, 0x990c, 0x98df, 0xff0c, 0x4e5f, 0x4e0d,
  0x518d, 0x9935, 0x5976, 0x3002, 0x000d, 0x000a,
  0x5712, 0x65b9, 0x4e0a, 0x9031, 0x516d, 0x5c07,
  0x7260, 0x79fb, 0x5230, 0x4fdd, 0x6eab, 0x7bb1,
  0x7528, 0x5976, 0x74f6, 0x4eba, 0x5de5, 0x9935,
  0x5976, 0xff0c, 0x96a8, 0x5f8c, 0x53c8, 0x8b93,
  0x7260, 0x56de, 0x5230, 0x6bcd, 0x89aa, 0x8eab,
  0x908a, 0xff0c, 0x7531, 0x201c, 0x771f, 0x771f,
  0x201d, 0x6bcd, 0x4e73, 0x5582, 0x990a, 0xff0c,
  0x4f46, 0x201c, 0x771f, 0x771f, 0x201d, 0x4e0d,
  0x518d, 0x5c0d, 0x5bf6, 0x5bf6, 0x8868, 0x793a,
  0x95dc, 0x5fc3, 0xff0c, 0x5712, 0x65b9, 0x53ea,
  0x5f97, 0x518d, 0x5ea6, 0x628a, 0x5bf6, 0x5bf6,
  0x653e, 0x56de, 0x4fdd, 0x6eab, 0x7bb1, 0x3002,
  0x000d, 0x000a
};
 
  int nrChar = sizeof(testdoc_utf16BE_txt) / sizeof(wc_t);
  ArrayWChar * pArray = new ArrayWChar(nrChar);
  for (int i = 0 ; i < nrChar; ++i)
     (*pArray)[i] = testdoc_utf16BE_txt[i];

  return pArray;
}

static MemoryStream * __GetUtf8Stream()
{
   u8_t testdoc_txt[] = {
  0xe8, 0xb2, 0x93, 0xe7, 0x86, 0x8a, 0xe5, 0xaf, 0xb6,
  0xe5, 0xaf, 0xb6, 0xe5, 0x87, 0xba, 0xe7, 0x94, 0x9f, 0xe5, 0xbe, 0x8c,
  0xe4, 0xb8, 0x80, 0xe5, 0xba, 0xa6, 0xe7, 0x96, 0x91, 0xe9, 0x81, 0xad,
  0xe6, 0xaf, 0x8d, 0xe8, 0xa6, 0xaa, 0xe2, 0x80, 0x9c, 0xe6, 0xa3, 0x84,
  0xe9, 0xa4, 0x8a, 0xe2, 0x80, 0x9d, 0xef, 0xbc, 0x8c, 0xe7, 0x94, 0x9f,
  0xe7, 0x94, 0xa2, 0xe5, 0xbe, 0x8c, 0xe4, 0xb8, 0x80, 0xe7, 0x9b, 0xb4,
  0xe6, 0x8a, 0x8a, 0xe5, 0xaf, 0xb6, 0xe5, 0xaf, 0xb6, 0xe6, 0x8a, 0xb1,
  0xe5, 0x9c, 0xa8, 0xe8, 0x83, 0xb8, 0xe5, 0x89, 0x8d, 0xe7, 0x9a, 0x84,
  0xe2, 0x80, 0x9c, 0xe7, 0x9c, 0x9f, 0xe7, 0x9c, 0x9f, 0xe2, 0x80, 0x9d,
  0xe7, 0xaa, 0x81, 0xe7, 0x84, 0xb6, 0xe6, 0x94, 0xbe, 0xe9, 0x96, 0x8b,
  0xe5, 0xad, 0xa9, 0xe5, 0xad, 0x90, 0xef, 0xbc, 0x8c, 0xe8, 0x87, 0xaa,
  0xe9, 0xa1, 0xa7, 0xe8, 0x87, 0xaa, 0xe5, 0x9c, 0xb0, 0xe5, 0x90, 0x83,
  0xe8, 0xb5, 0xb7, 0xe9, 0xa4, 0x8c, 0xe9, 0xa3, 0x9f, 0xef, 0xbc, 0x8c,
  0xe4, 0xb9, 0x9f, 0xe4, 0xb8, 0x8d, 0xe5, 0x86, 0x8d, 0xe9, 0xa4, 0xb5,
  0xe5, 0xa5, 0xb6, 0xe3, 0x80, 0x82, 0x0d, 0x0a, 0xe5, 0x9c, 0x92, 0xe6,
  0x96, 0xb9, 0xe4, 0xb8, 0x8a, 0xe9, 0x80, 0xb1, 0xe5, 0x85, 0xad, 0xe5,
  0xb0, 0x87, 0xe7, 0x89, 0xa0, 0xe7, 0xa7, 0xbb, 0xe5, 0x88, 0xb0, 0xe4,
  0xbf, 0x9d, 0xe6, 0xba, 0xab, 0xe7, 0xae, 0xb1, 0xe7, 0x94, 0xa8, 0xe5,
  0xa5, 0xb6, 0xe7, 0x93, 0xb6, 0xe4, 0xba, 0xba, 0xe5, 0xb7, 0xa5, 0xe9,
  0xa4, 0xb5, 0xe5, 0xa5, 0xb6, 0xef, 0xbc, 0x8c, 0xe9, 0x9a, 0xa8, 0xe5,
  0xbe, 0x8c, 0xe5, 0x8f, 0x88, 0xe8, 0xae, 0x93, 0xe7, 0x89, 0xa0, 0xe5,
  0x9b, 0x9e, 0xe5, 0x88, 0xb0, 0xe6, 0xaf, 0x8d, 0xe8, 0xa6, 0xaa, 0xe8,
  0xba, 0xab, 0xe9, 0x82, 0x8a, 0xef, 0xbc, 0x8c, 0xe7, 0x94, 0xb1, 0xe2,
  0x80, 0x9c, 0xe7, 0x9c, 0x9f, 0xe7, 0x9c, 0x9f, 0xe2, 0x80, 0x9d, 0xe6,
  0xaf, 0x8d, 0xe4, 0xb9, 0xb3, 0xe5, 0x96, 0x82, 0xe9, 0xa4, 0x8a, 0xef,
  0xbc, 0x8c, 0xe4, 0xbd, 0x86, 0xe2, 0x80, 0x9c, 0xe7, 0x9c, 0x9f, 0xe7,
  0x9c, 0x9f, 0xe2, 0x80, 0x9d, 0xe4, 0xb8, 0x8d, 0xe5, 0x86, 0x8d, 0xe5,
  0xb0, 0x8d, 0xe5, 0xaf, 0xb6, 0xe5, 0xaf, 0xb6, 0xe8, 0xa1, 0xa8, 0xe7,
  0xa4, 0xba, 0xe9, 0x97, 0x9c, 0xe5, 0xbf, 0x83, 0xef, 0xbc, 0x8c, 0xe5,
  0x9c, 0x92, 0xe6, 0x96, 0xb9, 0xe5, 0x8f, 0xaa, 0xe5, 0xbe, 0x97, 0xe5,
  0x86, 0x8d, 0xe5, 0xba, 0xa6, 0xe6, 0x8a, 0x8a, 0xe5, 0xaf, 0xb6, 0xe5,
  0xaf, 0xb6, 0xe6, 0x94, 0xbe, 0xe5, 0x9b, 0x9e, 0xe4, 0xbf, 0x9d, 0xe6,
  0xba, 0xab, 0xe7, 0xae, 0xb1, 0xe3, 0x80, 0x82, 0x0d, 0x0a
  };

  MemoryStream *pStream = new MemoryStream();
  for (int i = 0 ; i < sizeof(testdoc_txt); ++i) {
     pStream->Write(testdoc_txt[i]);
  }

  pStream->ResetPointer();
  return pStream;
}

static MemoryStream * __GetUtf16LEStream()
{
  u8_t testdoc_utf16LE_txt[] = {
  0x93, 0x8c, 0x8a, 0x71, 0xf6, 0x5b, 0xf6, 0x5b, 0xfa, 0x51,
  0x1f, 0x75, 0x8c, 0x5f, 0x00, 0x4e, 0xa6, 0x5e, 0x91, 0x75, 0x6d, 0x90,
  0xcd, 0x6b, 0xaa, 0x89, 0x1c, 0x20, 0xc4, 0x68, 0x0a, 0x99, 0x1d, 0x20,
  0x0c, 0xff, 0x1f, 0x75, 0x22, 0x75, 0x8c, 0x5f, 0x00, 0x4e, 0xf4, 0x76,
  0x8a, 0x62, 0xf6, 0x5b, 0xf6, 0x5b, 0xb1, 0x62, 0x28, 0x57, 0xf8, 0x80,
  0x4d, 0x52, 0x84, 0x76, 0x1c, 0x20, 0x1f, 0x77, 0x1f, 0x77, 0x1d, 0x20,
  0x81, 0x7a, 0x36, 0x71, 0x3e, 0x65, 0x8b, 0x95, 0x69, 0x5b, 0x50, 0x5b,
  0x0c, 0xff, 0xea, 0x81, 0x67, 0x98, 0xea, 0x81, 0x30, 0x57, 0x03, 0x54,
  0x77, 0x8d, 0x0c, 0x99, 0xdf, 0x98, 0x0c, 0xff, 0x5f, 0x4e, 0x0d, 0x4e,
  0x8d, 0x51, 0x35, 0x99, 0x76, 0x59, 0x02, 0x30, 0x0d, 0x00, 0x0a, 0x00,
  0x12, 0x57, 0xb9, 0x65, 0x0a, 0x4e, 0x31, 0x90, 0x6d, 0x51, 0x07, 0x5c,
  0x60, 0x72, 0xfb, 0x79, 0x30, 0x52, 0xdd, 0x4f, 0xab, 0x6e, 0xb1, 0x7b,
  0x28, 0x75, 0x76, 0x59, 0xf6, 0x74, 0xba, 0x4e, 0xe5, 0x5d, 0x35, 0x99,
  0x76, 0x59, 0x0c, 0xff, 0xa8, 0x96, 0x8c, 0x5f, 0xc8, 0x53, 0x93, 0x8b,
  0x60, 0x72, 0xde, 0x56, 0x30, 0x52, 0xcd, 0x6b, 0xaa, 0x89, 0xab, 0x8e,
  0x8a, 0x90, 0x0c, 0xff, 0x31, 0x75, 0x1c, 0x20, 0x1f, 0x77, 0x1f, 0x77,
  0x1d, 0x20, 0xcd, 0x6b, 0x73, 0x4e, 0x82, 0x55, 0x0a, 0x99, 0x0c, 0xff,
  0x46, 0x4f, 0x1c, 0x20, 0x1f, 0x77, 0x1f, 0x77, 0x1d, 0x20, 0x0d, 0x4e,
  0x8d, 0x51, 0x0d, 0x5c, 0xf6, 0x5b, 0xf6, 0x5b, 0x68, 0x88, 0x3a, 0x79,
  0xdc, 0x95, 0xc3, 0x5f, 0x0c, 0xff, 0x12, 0x57, 0xb9, 0x65, 0xea, 0x53,
  0x97, 0x5f, 0x8d, 0x51, 0xa6, 0x5e, 0x8a, 0x62, 0xf6, 0x5b, 0xf6, 0x5b,
  0x3e, 0x65, 0xde, 0x56, 0xdd, 0x4f, 0xab, 0x6e, 0xb1, 0x7b, 0x02, 0x30,
  0x0d, 0x00, 0x0a, 0x00
};

  MemoryStream *pStream = new MemoryStream();
  for (int i = 0 ; i < sizeof(testdoc_utf16LE_txt); ++i) {
     pStream->Write(testdoc_utf16LE_txt[i]);
  }

  pStream->ResetPointer();
  return pStream;
}

static MemoryStream * __GetUtf16BEStream()
{
unsigned char testdoc_utf16BE_txt[] = {
  0x8c, 0x93, 0x71, 0x8a, 0x5b, 0xf6, 0x5b, 0xf6, 0x51, 0xfa,
  0x75, 0x1f, 0x5f, 0x8c, 0x4e, 0x00, 0x5e, 0xa6, 0x75, 0x91, 0x90, 0x6d,
  0x6b, 0xcd, 0x89, 0xaa, 0x20, 0x1c, 0x68, 0xc4, 0x99, 0x0a, 0x20, 0x1d,
  0xff, 0x0c, 0x75, 0x1f, 0x75, 0x22, 0x5f, 0x8c, 0x4e, 0x00, 0x76, 0xf4,
  0x62, 0x8a, 0x5b, 0xf6, 0x5b, 0xf6, 0x62, 0xb1, 0x57, 0x28, 0x80, 0xf8,
  0x52, 0x4d, 0x76, 0x84, 0x20, 0x1c, 0x77, 0x1f, 0x77, 0x1f, 0x20, 0x1d,
  0x7a, 0x81, 0x71, 0x36, 0x65, 0x3e, 0x95, 0x8b, 0x5b, 0x69, 0x5b, 0x50,
  0xff, 0x0c, 0x81, 0xea, 0x98, 0x67, 0x81, 0xea, 0x57, 0x30, 0x54, 0x03,
  0x8d, 0x77, 0x99, 0x0c, 0x98, 0xdf, 0xff, 0x0c, 0x4e, 0x5f, 0x4e, 0x0d,
  0x51, 0x8d, 0x99, 0x35, 0x59, 0x76, 0x30, 0x02, 0x00, 0x0d, 0x00, 0x0a,
  0x57, 0x12, 0x65, 0xb9, 0x4e, 0x0a, 0x90, 0x31, 0x51, 0x6d, 0x5c, 0x07,
  0x72, 0x60, 0x79, 0xfb, 0x52, 0x30, 0x4f, 0xdd, 0x6e, 0xab, 0x7b, 0xb1,
  0x75, 0x28, 0x59, 0x76, 0x74, 0xf6, 0x4e, 0xba, 0x5d, 0xe5, 0x99, 0x35,
  0x59, 0x76, 0xff, 0x0c, 0x96, 0xa8, 0x5f, 0x8c, 0x53, 0xc8, 0x8b, 0x93,
  0x72, 0x60, 0x56, 0xde, 0x52, 0x30, 0x6b, 0xcd, 0x89, 0xaa, 0x8e, 0xab,
  0x90, 0x8a, 0xff, 0x0c, 0x75, 0x31, 0x20, 0x1c, 0x77, 0x1f, 0x77, 0x1f,
  0x20, 0x1d, 0x6b, 0xcd, 0x4e, 0x73, 0x55, 0x82, 0x99, 0x0a, 0xff, 0x0c,
  0x4f, 0x46, 0x20, 0x1c, 0x77, 0x1f, 0x77, 0x1f, 0x20, 0x1d, 0x4e, 0x0d,
  0x51, 0x8d, 0x5c, 0x0d, 0x5b, 0xf6, 0x5b, 0xf6, 0x88, 0x68, 0x79, 0x3a,
  0x95, 0xdc, 0x5f, 0xc3, 0xff, 0x0c, 0x57, 0x12, 0x65, 0xb9, 0x53, 0xea,
  0x5f, 0x97, 0x51, 0x8d, 0x5e, 0xa6, 0x62, 0x8a, 0x5b, 0xf6, 0x5b, 0xf6,
  0x65, 0x3e, 0x56, 0xde, 0x4f, 0xdd, 0x6e, 0xab, 0x7b, 0xb1, 0x30, 0x02,
  0x00, 0x0d, 0x00, 0x0a
};

  MemoryStream *pStream = new MemoryStream();
  for (int i = 0 ; i < sizeof(testdoc_utf16BE_txt); ++i) {
     pStream->Write(testdoc_utf16BE_txt[i]);
  }

  pStream->ResetPointer();
  return pStream;
}

static void ClearArray(ArrayWChar &anArray)
{
   for (int i = 0; i < static_cast<int>(anArray.GetSize()); ++i) {
      anArray[i] = 0;
   }
}

static void TestStreamReader()
{
   debug::Print(_S("Testing stream reader...\n"));

   cppmempool::MemPoolWrap memPool;

   ArrayWChar *pOrgArray = __GetOriginalCharacters();
   ArrayWChar *pNewArray = new ArrayWChar(pOrgArray->GetSize());

   // utf-8
   StreamReader *pReader = new StreamReader(__GetUtf8Stream(), text::CS_UTF8);
   for (int i = 0; i < static_cast<int>(pOrgArray->GetSize()); ++i) {
      assert((*pOrgArray)[i] == static_cast<wc_t>(pReader->Read()));
   }
   assert(pReader->Read() == -1);
   pReader->Close();

   pReader = new StreamReader(__GetUtf8Stream(), text::CS_UTF8);
   assert(pReader->Read(*pNewArray) == static_cast<int>(pNewArray->GetSize())); // read by array
   for (int i = 0; i < static_cast<int>(pOrgArray->GetSize()); ++i) {
      assert((*pOrgArray)[i] == (*pNewArray)[i]);
   }
   assert(pReader->Read() == -1);
   pReader->Close();
   ClearArray(*pNewArray);

   // utf-16 LE
   pReader = new StreamReader(__GetUtf16LEStream(), text::CS_UTF16LE);
   for (int i = 0; i < static_cast<int>(pOrgArray->GetSize()); ++i) {
      assert((*pOrgArray)[i] == static_cast<wc_t>(pReader->Read()));
   }
   assert(pReader->Read() == -1);
   pReader->Close();

   pReader = new StreamReader(__GetUtf16LEStream(), text::CS_UTF16LE);
   assert(pReader->Read(*pNewArray) == static_cast<int>(pNewArray->GetSize())); // read by array
   for (int i = 0; i < static_cast<int>(pOrgArray->GetSize()); ++i) {
      assert((*pOrgArray)[i] == (*pNewArray)[i]);
   }
   assert(pReader->Read() == -1);
   pReader->Close();
   ClearArray(*pNewArray);

   // utf-16 BE
   pReader = new StreamReader(__GetUtf16BEStream(), text::CS_UTF16BE);
   for (int i = 0; i < static_cast<int>(pOrgArray->GetSize()); ++i) {
      assert((*pOrgArray)[i] == static_cast<wc_t>(pReader->Read()));
   }
   assert(pReader->Read() == -1);
   pReader->Close();

   pReader = new StreamReader(__GetUtf16BEStream(), text::CS_UTF16BE);
   assert(pReader->Read(*pNewArray) == static_cast<int>(pNewArray->GetSize())); // read by array
   for (int i = 0; i < static_cast<int>(pOrgArray->GetSize()); ++i) {
      assert((*pOrgArray)[i] == (*pNewArray)[i]);
   }
   assert(pReader->Read() == -1);
   pReader->Close();
   ClearArray(*pNewArray);

}

static void TestBufferedReader()
{
   debug::Print(_S("Testing buffered reader...\n"));

   cppmempool::MemPoolWrap memPool;

   const int ARRAYSIZE = 26;
   ArrayByte * buffer = new ArrayByte(ARRAYSIZE);
   for (u32_t i = 0; i < buffer->GetSize(); ++i) {
      (*buffer)[i] = i + 97;
   }

   MemoryStream * memStream = new MemoryStream();
   assert(memStream->GetBufferSize() == 0);
   memStream->Write(*buffer);
   memStream->ResetPointer();

   StreamReader * sReader = new StreamReader(memStream, text::CS_UTF8);
   BufferedReader *bufReader = new BufferedReader(sReader, 5);
   ArrayWChar *readBuf = new ArrayWChar(ARRAYSIZE);
   
   assert(bufReader->Read(*readBuf, 0, 3) == 3);
   assert(bufReader->Read(*readBuf, 0, 10) == 10);
   bufReader->Skip(-4);
   assert(bufReader->CanReadNoBlocking() == 4);
   assert(bufReader->Read() == _S('j'));
   assert(bufReader->Read() == _S('k'));
   assert(bufReader->Read() == _S('l'));
   assert(bufReader->Read() == _S('m'));
   assert(bufReader->Read(*readBuf, 0, 6) == 6);
   assert((*readBuf)[0] == _S('n'));
   assert((*readBuf)[1] == _S('o'));
   assert((*readBuf)[2] == _S('p'));
   assert((*readBuf)[3] == _S('q'));
   assert((*readBuf)[4] == _S('r'));
   assert((*readBuf)[5] == _S('s'));
   bufReader->Skip(-1);
   assert(bufReader->CanReadNoBlocking() == 1);
   assert(bufReader->Read(*readBuf, 0, 8) > 0); // may not equal to 8
   assert((*readBuf)[0] == _S('s'));
}

static void TestStringWriter()
{
   debug::Print(_S("Testing string writer...\n"));

   cppmempool::MemPoolWrap memPool;
   
   ArrayWChar *pArray = new ArrayWChar(128);
   StringWriter *pStringWriter = new StringWriter(10);

   for (int i = 0; i < 26; ++i)
      (*pArray)[i] = _S('A') + i;
   pStringWriter->Write(*pArray, 0, 26);
   pStringWriter->Write(0x61);
   pStringWriter->Write(0x62);
   pStringWriter->Write(0x63);

   assert(pStringWriter->GetStringBuffer().Compare(_S("ABCDEFGHIJKLMNOPQRSTUVWXYZabc")) == 0);

   pStringWriter->Write(CFString(_S("gogoggo")));   
   assert(pStringWriter->GetStringBuffer().Compare(_S("ABCDEFGHIJKLMNOPQRSTUVWXYZabcgogoggo")) == 0);

   pStringWriter->Write(CFString(_S("1234567890")), 3, 5);   
   assert(pStringWriter->GetStringBuffer().Compare(_S("ABCDEFGHIJKLMNOPQRSTUVWXYZabcgogoggo45678")) == 0);
}

static void TestStreamWriter()
{
   debug::Print(_S("Testing stream writer...\n"));

   cppmempool::MemPoolWrap memPool;
   
   ArrayWChar *pArray = new ArrayWChar(128);
   MemoryStream *pMemStream = new MemoryStream();
   // UTF-8
   StreamWriter *pStreamWriter = new StreamWriter(pMemStream, text::CS_UTF8);

   for (int i = 0; i < 26; ++i)
      (*pArray)[i] = _S('A') + i;
   pStreamWriter->Write(*pArray, 0, 26);
   pStreamWriter->Write(0x61);
   pStreamWriter->Write(0x62);
   pStreamWriter->Write(0x63);

   ArrayByte *pByteArray = new ArrayByte(128);
   pMemStream->ResetPointer();
   assert(pMemStream->Read(*pByteArray) == 29);
   for (int i = 0; i < 26; ++i) {
      assert((*pByteArray)[i] == ('A' + i));
   }
   assert((*pByteArray)[26] == 'a');
   assert((*pByteArray)[27] == 'b');
   assert((*pByteArray)[28] == 'c');

   pStreamWriter->Write(CFString(_S("gogoggo")));
   pMemStream->Seek(29, Stream::S_BEGIN);
   assert(pMemStream->Read(*pByteArray) == 7);
   assert((*pByteArray)[0] == 'g');
   assert((*pByteArray)[1] == 'o');
   assert((*pByteArray)[2] == 'g');
   assert((*pByteArray)[3] == 'o');
   assert((*pByteArray)[4] == 'g');
   assert((*pByteArray)[5] == 'g');
   assert((*pByteArray)[6] == 'o');

   pStreamWriter->Write(CFString(_S("1234567890")), 3, 5);   
   pMemStream->Seek(36, Stream::S_BEGIN);
   assert(pMemStream->Read(*pByteArray) == 5);
   assert((*pByteArray)[0] == '4');
   assert((*pByteArray)[1] == '5');
   assert((*pByteArray)[2] == '6');
   assert((*pByteArray)[3] == '7');
   assert((*pByteArray)[4] == '8');

   // UTF-16LE
   pMemStream->ResetPointerAndClearBuffer();
   pStreamWriter = new StreamWriter(pMemStream, text::CS_UTF16LE);

   for (int i = 0; i < 26; ++i)
      (*pArray)[i] = _S('A') + i;
   pStreamWriter->Write(*pArray, 0, 26);
   pStreamWriter->Write(0x61);
   pStreamWriter->Write(0x62);
   pStreamWriter->Write(0x63);

   pMemStream->ResetPointer();
   assert(pMemStream->Read(*pByteArray) == 58);
   for (int i = 0; i < 52; i += 2) {
      assert((*pByteArray)[i] == ('A' + (i/2)));
      assert((*pByteArray)[i + 1] == '\0');
   }
   assert((*pByteArray)[52] == 'a');
   assert((*pByteArray)[53] == '\0');
   assert((*pByteArray)[54] == 'b');
   assert((*pByteArray)[55] == '\0');
   assert((*pByteArray)[56] == 'c');
   assert((*pByteArray)[57] == '\0');
   
   pStreamWriter->Write(CFString(_S("gogoggo")));
   pMemStream->Seek(58, Stream::S_BEGIN);
   assert(pMemStream->Read(*pByteArray) == 14);
   assert((*pByteArray)[0] == 'g');
   assert((*pByteArray)[1] == '\0');
   assert((*pByteArray)[2] == 'o');
   assert((*pByteArray)[3] == '\0');
   assert((*pByteArray)[4] == 'g');
   assert((*pByteArray)[5] == '\0');
   assert((*pByteArray)[6] == 'o');
   assert((*pByteArray)[7] == '\0');
   assert((*pByteArray)[8] == 'g');
   assert((*pByteArray)[9] == '\0');
   assert((*pByteArray)[10] == 'g');
   assert((*pByteArray)[11] == '\0');
   assert((*pByteArray)[12] == 'o');
   assert((*pByteArray)[13] == '\0');

   pStreamWriter->Write(CFString(_S("1234567890")), 3, 5);   
   pMemStream->Seek(72, Stream::S_BEGIN);
   assert(pMemStream->Read(*pByteArray) == 10);
   assert((*pByteArray)[0] == '4');
   assert((*pByteArray)[1] == '\0');
   assert((*pByteArray)[2] == '5');
   assert((*pByteArray)[3] == '\0');
   assert((*pByteArray)[4] == '6');
   assert((*pByteArray)[5] == '\0');
   assert((*pByteArray)[6] == '7');
   assert((*pByteArray)[7] == '\0');
   assert((*pByteArray)[8] == '8');
   assert((*pByteArray)[9] == '\0');

   // UTF-16BE
   pMemStream->ResetPointerAndClearBuffer();
   pStreamWriter = new StreamWriter(pMemStream, text::CS_UTF16BE);

   for (int i = 0; i < 26; ++i)
      (*pArray)[i] = _S('A') + i;
   pStreamWriter->Write(*pArray, 0, 26);
   pStreamWriter->Write(0x61);
   pStreamWriter->Write(0x62);
   pStreamWriter->Write(0x63);

   pMemStream->ResetPointer();
   assert(pMemStream->Read(*pByteArray) == 58);
   for (int i = 0; i < 52; i += 2) {
      assert((*pByteArray)[i] == '\0');
      assert((*pByteArray)[i + 1] == ('A' + (i/2)));
   }
   assert((*pByteArray)[52] == '\0');
   assert((*pByteArray)[53] == 'a');
   assert((*pByteArray)[54] == '\0');
   assert((*pByteArray)[55] == 'b');
   assert((*pByteArray)[56] == '\0');
   assert((*pByteArray)[57] == 'c');

   pStreamWriter->Write(CFString(_S("gogoggo")));
   pMemStream->Seek(58, Stream::S_BEGIN);
   assert(pMemStream->Read(*pByteArray) == 14);
   assert((*pByteArray)[0] == '\0');
   assert((*pByteArray)[1] == 'g');
   assert((*pByteArray)[2] == '\0');
   assert((*pByteArray)[3] == 'o');
   assert((*pByteArray)[4] == '\0');
   assert((*pByteArray)[5] == 'g');
   assert((*pByteArray)[6] == '\0');
   assert((*pByteArray)[7] == 'o');
   assert((*pByteArray)[8] == '\0');
   assert((*pByteArray)[9] == 'g');
   assert((*pByteArray)[10] == '\0');
   assert((*pByteArray)[11] == 'g');
   assert((*pByteArray)[12] == '\0');
   assert((*pByteArray)[13] == 'o');

   pStreamWriter->Write(CFString(_S("1234567890")), 3, 5);   
   pMemStream->Seek(72, Stream::S_BEGIN);
   assert(pMemStream->Read(*pByteArray) == 10);
   assert((*pByteArray)[0] == '\0');
   assert((*pByteArray)[1] == '4');
   assert((*pByteArray)[2] == '\0');
   assert((*pByteArray)[3] == '5');
   assert((*pByteArray)[4] == '\0');
   assert((*pByteArray)[5] == '6');
   assert((*pByteArray)[6] == '\0');
   assert((*pByteArray)[7] == '7');
   assert((*pByteArray)[8] == '\0');
   assert((*pByteArray)[9] == '8');
}



void TestIO(void)
{
   debug::Print(_S("Testing read/write UTF16LE files...\n"));

   // UTF16 LE
   TestReadWriteDel_UTF16Normal(_S("hello.txt"), FileStream::ENC_UTF16LE);
   TestReadWriteDel_UTF16NoByte(_S("hello.txt"), FileStream::ENC_UTF16LE);
   TestReadWriteDel_UTF16SingleByte(_S("hello.txt"), FileStream::ENC_UTF16LE);
   TestReadWriteDel_UTF16OddNumByte(_S("hello.txt"), FileStream::ENC_UTF16LE);
   TestReadWriteDel_UTF16LastLineNoLineFeed(_S("hello.txt"), FileStream::ENC_UTF16LE);
   TestReadWriteDel_UTF16LongLine(_S("hello.txt"), FileStream::ENC_UTF16LE);
   TestReadWriteDel_UTF16_2LongLines(_S("hello.txt"), FileStream::ENC_UTF16LE);

   debug::Print(_S("Testing read/write UTF16BE files...\n"));

   // UTF16 BE
   TestReadWriteDel_UTF16Normal(_S("hello.txt"), FileStream::ENC_UTF16BE);
   TestReadWriteDel_UTF16NoByte(_S("hello.txt"), FileStream::ENC_UTF16BE);
   TestReadWriteDel_UTF16SingleByte(_S("hello.txt"), FileStream::ENC_UTF16BE);
   TestReadWriteDel_UTF16OddNumByte(_S("hello.txt"), FileStream::ENC_UTF16BE);
   TestReadWriteDel_UTF16LastLineNoLineFeed(_S("hello.txt"), FileStream::ENC_UTF16BE);
   TestReadWriteDel_UTF16LongLine(_S("hello.txt"), FileStream::ENC_UTF16BE);
   TestReadWriteDel_UTF16_2LongLines(_S("hello.txt"), FileStream::ENC_UTF16BE);

   debug::Print(_S("Testing read/write UTF8 files...\n"));

   // UTF8
   TestReadWriteDel_UTF8Normal(_S("hello.txt"));
   TestReadWriteDel_UTF8NoByte(_S("hello.txt"));
   TestReadWriteDel_UTF8LastLineNoLineFeed(_S("hello.txt"));
   TestReadWriteDel_UTF8LongLine(_S("hello.txt"));
   TestReadWriteDel_UTF8_2LongLines(_S("hello.txt"));

   TestAppendFile(_S("hello.txt"));
   //TestReadNonExistingFile(_S("__hello.txt"));

   TestMemoryStream();
   TestBufferedReadStream();
   TestStreamReader();
   TestBufferedReader();

   TestStringWriter();
   TestStreamWriter();
}
